<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Set-Map-WeakSet基本使用</title>
  <!-- 
  WeakSet  是 JavaScript ES6 中引入的一种集合类型，类似于  Set ，但具有一些独特的特性。 
  一、WeakSet 的定义
  WeakSet  是一种只允许对象作为元素的集合，并且对这些对象的引用是弱引用。这意味着，如果没有其他引用指向这些对象，它们会被垃圾回收机制自动回收。

  二、创建 WeakSet
  使用  new WeakSet()  创建一个新的  WeakSet  实例：
  const myWeakSet = new WeakSet();
  三、基本操作
   1. 添加元素
  使用  add(value)  方法向  WeakSet  中添加元素。注意，添加的值必须是对象。
  const obj1 = { name: '小明' };
  const obj2 = { name: '小红' };

  myWeakSet.add(obj1);
  myWeakSet.add(obj2);
   2. 检查元素
  使用  has(value)  方法检查  WeakSet  中是否存在某个对象。
  console.log(myWeakSet.has(obj1)); // 输出: true
  console.log(myWeakSet.has(obj2)); // 输出: true
   3. 删除元素
  使用  delete(value)  方法删除  WeakSet  中的元素。
  myWeakSet.delete(obj1);
  console.log(myWeakSet.has(obj1)); // 输出: false

  四、WeakSet 的特点
  1. 弱引用：
    -  WeakSet  中的对象是弱引用，这意味着如果没有其他引用指向这些对象，它们会被垃圾回收机制自动回收。

  2. 只能存储对象：
    -  WeakSet  只能存储对象，不能存储基本数据类型（如字符串、数字、布尔值等）。

  3. 不可迭代：
    -  WeakSet  不支持迭代，因此不能使用  for...of  循环或其他迭代方法。

  4. 没有  size  属性：
    -  WeakSet  没有  size  属性，无法直接获取集合中元素的数量。

  五、使用场景
  WeakSet  适合用于以下场景：
  - 缓存对象：当需要缓存一些对象，但不希望阻止这些对象被垃圾回收时，可以使用  WeakSet 。
  - 跟踪对象的状态：可以使用  WeakSet  来跟踪某些对象的状态，例如标记哪些对象已经被处理过。

  六、总结
  -  WeakSet  是一种只允许对象作为元素的集合，具有弱引用特性。
  - 主要方法包括  add() 、 has()  和  delete() ，但不支持迭代和  size  属性。注意: 没有set()方法
  - 适合用于需要自动垃圾回收的对象管理场景。
  -->
</head>

<body>

  <script>

    // Weak Referance(弱引用) 和 Strong Referance(强引用)
    let obj1 = { name: '小红' };
    let obj2 = { name: '小明' };
    let arr = [obj1, obj2];
    obj1 = null;
    obj2 = null;
    console.log(arr); // [obj1, obj2]

    const set = new Set();
    arr = null
    console.log(set); // Set(0) {size: 0}

    // WeakSet 的用法
    const myWeakSet = new WeakSet();
    const info1 = { name: '小红' };
    const info2 = { name: '小明' };
    myWeakSet.add(info1);
    myWeakSet.add(info2);
    // myWeakSet.set(info1.name, 'aaaa') // 没有set()方法
    console.log(myWeakSet.has(info1)); // 输出: true

    // WeakSet 的使用场景
    // 1. 缓存对象
    const cache = new WeakSet();
    function process(obj) {
      if (cache.has(obj)) {
        console.log('对象已缓存');
        return;
      }
      cache.add(obj);
      // 处理对象的逻辑
    }
    const obj = { name: '小红' };
    process(obj);
    process(obj); // 对象已缓存

    // 2. 跟踪对象的状态
    const trackedObjects = new WeakSet();
    function track(obj) {
      trackedObjects.add(obj);
    }
    function untrack(obj) {
      trackedObjects.delete(obj);
    }
    function isTracked(obj) {
      return trackedObjects.has(obj);
    }
    const info3 = { name: '小红' };
    track(info3);
    console.log(isTracked(info3)); // 输出: true
    untrack(info3);

    // 3. 防止内存泄漏
    const createWeakSet = new WeakSet();
    function createObject() {
      const obj = { name: '小红' };
      createWeakSet.add(obj);
      return obj;
    }
    const resCreateObjectF = createObject();
    console.log(resCreateObjectF.name); // 输出: 小红
    // resCreateObjectF = null;  // Uncaught TypeError: Invalid value used in weak set

    // 4. 防止对象被垃圾回收
    const preventGC = new WeakSet();
    function prevent(obj) {
      preventGC.add(obj);
    }
    function allowGC(obj) {
      preventGC.delete(obj);
    }
    const info4 = { name: '小红' };
    prevent(info4);
    console.log(info4.name); // 输出: 小红
    allowGC(info4); // 允许垃圾回收

    // 5. WeakSet 和 Set的区别
    // 5.1 WeakSet 只能存储对象，不能存储基本类型值
    const weakSet = new WeakSet();
    const mySet = new Set();
    // weakSet.add(1); // TypeError: Invalid value used in weak set
    // mySet.add(1); // 1

    // 5.2 WeakSet 对象中的引用是弱引用，即垃圾回收机制会自动回收 WeakSet 中存储的对象
    // 5.3 WeakSet 没有 size 属性，也不能遍历
    // 5.4 WeakSet 没有 clear 方法

    // 3.WeakSet的应用
    const pWeakSet = new WeakSet()
    class Person {
      constructor() {
        pWeakSet.add(this)
      }

      running() {
        if (!pWeakSet.has(this)) {
          console.log("Type error: 调用的方式不对")
          return
        }
        console.log("running~")
      }
    }

    let p = new Person()
    // p = null
    p.running()
    const runFn = p.running
    runFn()
    const info5 = { run: runFn }
    info5.run()

  </script>

</body>

</html>